<template>
  <uploader 
          ref="uploader"
          :autoStart="false" 
          @file-added="onFileAdded"
          class="uploader-app">
    <uploader-unsupport></uploader-unsupport>
    <uploader-drop>
      <p>拖动文件</p>
      <uploader-btn>选择文件</uploader-btn>
    </uploader-drop>
    <uploader-list></uploader-list>
  </uploader>
</template>

<script>

  import SparkMD5 from 'spark-md5';
  import axios from 'axios'

  export default {
    data () {
      return {
        urlPrex: 'proxy/minio',
        uploadUrls:{}
      }
    },
    created() {
        //const uploaderInstance = this.$refs.uploader;
    },
    mounted () {
      this.$nextTick(() => {
        window.uploader = this.$refs.uploader.uploader
      })
    },
    methods: {
        onFileAdded(file) {
          file.urlPrex = this.urlPrex;
          // 计算MD5
          this.computeMD5(file);
        },
        getSuccessChunks(file) {
          return new Promise((resolve, reject) => {
            axios.get(file.urlPrex + '/get_chunks', {params :{
              md5: file.uniqueIdentifier,
            }}).then(function (response) {
              if(response.data.code==200){
                  file.uploadId = response.data.data.uploadId;
                  file.uuid = response.data.data.uuid;
                  file.uploaded = response.data.data.uploaded;
                  file.successChunks = response.data.data.chunks;
                  console.log("从后台获取的已上传的分片:",file.successChunks)
                  resolve(response);
              }else{
                console.log("获取已上传分片失败")
              } 
            }).catch(function (error) {
              console.log(error);
              reject(error);
            });
          })
        },
        newMultiUpload(file) {
          return new Promise((resolve, reject) => {
            axios.get(file.urlPrex + '/add_upload_record', {params :{
              totalChunks: file.totalChunkCounts,
              md5: file.uniqueIdentifier,
              size: file.size,
              fileName: file.name
            }}).then(function (response) {
              file.uploadId = response.data.uploadId;
              file.uuid = response.data.uuid;
              resolve(response);
            }).catch(function (error) {
              console.log(error);
              reject(error);
            });
          })
        },
        multipartUpload(file) {
          //当前分片的上传地址
          let chunkUploadUrl;
          let successChunks = file.successChunks;
          let blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice,
            chunkSize = 1024*1024*8,
            chunks = Math.ceil(file.size / chunkSize),
            currentChunk = 0,
            fileReader = new FileReader(),
            time = new Date().getTime();
          //读取下一个分片
          function loadNext() {
            let start = currentChunk * chunkSize;
            let end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;
            fileReader.readAsArrayBuffer(blobSlice.call(file.file, start, end));
          }
          //判断当前分片是否在已经上传分片中
          function checkSuccessChunks() {
            if(successChunks){
              var index = successChunks.indexOf((currentChunk+1))
              if (index == -1) {
                return false;
              }else{
                return true;
              }
            }else{
                return false;
            }
          }
          function getUploadChunkUrl(currentChunk) {
            return new Promise((resolve, reject) => {
                  axios.get(file.urlPrex + '/get_multipart_url_v2', {params :{
                    md5: file.uniqueIdentifier,
                    partNumber: currentChunk+1
                  }}).then( (response) =>{
                    if(response.data.code==200){
                      chunkUploadUrl = response.data.data.url;
                      console.log("当前分片:%s 获取到的上传地址:%s",currentChunk,chunkUploadUrl)
                    }else{
                       console.log("获取分片上传地址异常");
                    }
                    resolve(response);
                  }).catch(function (error) {
                    console.log(error);
                    reject(error);
                  });
            })
          }
          function uploadMinio(url, e) {
            return new Promise((resolve, reject) => {
              axios.put(url, e.target.result).then((res)=> {
                  console.log("当前分片:%c 上传存储服务成功",currentChunk)
                  resolve(res);
                }).catch(function (err) {
                  console.log(err);
                  reject(err);
                });
            });
          }
          async function uploadChunk(e) {
            if (!checkSuccessChunks()) {
                //获取分片上传url
                await getUploadChunkUrl(currentChunk);
                if (chunkUploadUrl != "") {
                  //上传到minio
                  await uploadMinio(chunkUploadUrl, e);
                } else {
                  return;
                }
            }
          };
          function completeUpload(){
            return new Promise((resolve, reject) => {
                axios.get(file.urlPrex + '/complete_multipart', {params :{
                  md5: file.uniqueIdentifier,
                }}).then( (response) =>{
                  if(response.data.code==200){
                     console.log("分片合并成功")
                  }
                  resolve(response);
                }).catch(function (error) {
                  console.log(error);
                  reject(error);
                });
              })
          }
          loadNext();
          fileReader.onload = async (e) => {
            await uploadChunk(e);
            fileReader.abort();
            currentChunk++;
            if (currentChunk < chunks) {
                console.log(`第${currentChunk}个分片上传完成, 开始第${currentChunk +1}/${chunks}个分片上传`);
                await loadNext();
            } else {
                await completeUpload();
                console.log(`文件上传完成：${file.name} \n分片：${chunks} 大小:${file.size} 用时：${(new Date().getTime() - time)/1000} s`);
                //window.location.reload();
            }
          };
        },
        //计算MD5
        computeMD5(file) {
            let blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice,
                chunkSize = 1024*1024*8,
                chunks = Math.ceil(file.size / chunkSize),
                currentChunk = 0,
                spark = new SparkMD5.ArrayBuffer(),
                fileReader = new FileReader();
            let time = new Date().getTime();
            file.totalChunkCounts = chunks;
            console.log('文件MD5计算中...')
            loadNext();
            fileReader.onload = (e) => {
                spark.append(e.target.result);   // Append array buffer
                currentChunk++;
                if (currentChunk < chunks) {
                    console.log(`第${currentChunk}分片解析完成, 开始第${currentChunk +1}/${chunks}分片解析`);
                    loadNext();
                } else {
                    let md5 = spark.end();
                    console.log(`MD5计算完成：${file.name} \nMD5：${md5} \n分片：${chunks} 大小:${file.size} 用时：${(new Date().getTime() - time)/1000} s`);
                    spark.destroy(); //释放缓存
                    file.uniqueIdentifier = md5; //将文件md5赋值给文件唯一标识
                    file.cmd5 = false; //取消计算md5状态
                    this.computeMD5Success(file);
                }
            };
            fileReader.onerror = () => {
                console.warn('oops, something went wrong.');
                file.cancel();
            };
            function loadNext() {
                let start = currentChunk * chunkSize;
                let end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;
                fileReader.readAsArrayBuffer(blobSlice.call(file.file, start, end));
            }
        },
        async computeMD5Success(file) {
            await this.getSuccessChunks(file);
            if (!file.uploadId && !file.uuid) {
              console.log("文件md5:%c 没有上传记录 生成新的上传记录并开始上传");
              await this.newMultiUpload(file);
              this.multipartUpload(file);
            } else {
              if (file.uploaded == "1") {  //已上传成功
                console.log("文件已经成功上传,进行秒传操作");
              } else {
                console.log("文件已上传,但是未上传成功进行断点续传");
                this.multipartUpload(file);
              }
            }
        }
    }
  }
</script>

<style>
  .uploader-app {
    width: 850px;
    padding: 15px;
    margin: 40px auto 0;
    font-size: 12px;
    box-shadow: 0 0 10px rgba(0, 0, 0, .4);
  }
  .uploader-app .uploader-btn {
    margin-right: 40px;
  }
  .uploader-app .uploader-list {
    max-height: 440px;
    overflow: auto;
    overflow-x: hidden;
    overflow-y: auto;
  }
</style>
